//
//  XLFormDescriptor.m
//  XLForm ( https://github.com/xmartlabs/XLForm )
//
//  Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com )
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.


#import "Form.h"

@interface Form()
@property NSMutableArray * sections; //展示的Section
@property (readonly) NSMutableDictionary* allRowsByTag;
@end

@implementation Form
-(instancetype)init
{
    self = [super init];
    if (self){
        _sections = [NSMutableArray array];
        _allRowsByTag = [NSMutableDictionary dictionary];
        _rowNavigationOptions = XLFormRowNavigationOptionEnabled;
        [self addObserver:self forKeyPath:@"sections" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:0];
    }
    return self;
}

+(instancetype)form
{
    return [[[self class] alloc] init];
}

-(void)addSection:(Section *)formSection
{
    [self insertObject:formSection inAllSectionsAtIndex:[self.sections count]];
}

-(void)addSection:(Section *)formSection atIndex:(NSUInteger)index
{
    if (index == 0){
        [self insertObject:formSection inAllSectionsAtIndex:0];
    }
    else{
        Section* previousSection = [self.sections objectAtIndex:MIN(self.sections.count, index-1)];
        [self addSection:formSection afterSection:previousSection];
    }
}

-(void)addSection:(Section *)formSection afterSection:(Section *)afterSection
{
    NSUInteger sectionIndex;
    NSUInteger allSectionIndex;
    if ((sectionIndex = [self.sections indexOfObject:formSection]) == NSNotFound){
        allSectionIndex = [self.sections indexOfObject:afterSection];
        if (allSectionIndex != NSNotFound) {
            [self insertObject:formSection inAllSectionsAtIndex:(allSectionIndex + 1)];
        }
        else { //case when afterSection does not exist. Just insert at the end.
            [self addSection:formSection];
            return;
        }
    }
}

-(void)removeSectionAtIndex:(NSUInteger)index
{
    if (self.sections.count > index){
        [self.sections removeObjectAtIndex:index];
    }
}

-(void)removeSection:(Section *)formSection
{
    NSUInteger index = NSNotFound;
    if ((index = [self.sections indexOfObject:formSection]) != NSNotFound){
        [self removeSectionAtIndex:index];
    }
}

-(Section *)sectionAtIndex:(NSUInteger)index
{
    return [self.sections objectAtIndex:index];
}

#pragma mark - Row
-(void)addRow:(Row *)formRow beforeRow:(Row *)beforeRow
{
    if (beforeRow.section){
        [beforeRow.section addRow:formRow beforeRow:beforeRow];
    }
    else{
        [[self.sections lastObject] addRow:formRow beforeRow:beforeRow];
    }
}

-(void)addRow:(Row *)formRow beforeRowTag:(NSString *)beforeRowTag
{
    Row * beforeRowForm = [self rowWithTag:beforeRowTag];
    [self addRow:formRow beforeRow:beforeRowForm];
}

-(void)addRow:(Row *)formRow afterRow:(Row *)afterRow
{
    if (afterRow.section){
        [afterRow.section addRow:formRow afterRow:afterRow];
    }
    else{
        [[self.sections lastObject] addRow:formRow afterRow:afterRow];
    }
}

-(void)addRow:(Row *)formRow afterRowTag:(NSString *)afterRowTag
{
    Row * afterRowForm = [self rowWithTag:afterRowTag];
    [self addRow:formRow afterRow:afterRowForm];
}

-(void)removeRow:(Row *)formRow
{
    for (Section * section in self.sections){
        if ([section.rows containsObject:formRow]){
            [section removeRow:formRow];
        }
    }
}

-(Row *)rowWithTag:(NSString *)tag
{
    return self.allRowsByTag[tag];
}


-(void)removeRowWithTag:(NSString *)tag
{
    Row * formRow = [self rowWithTag:tag];
    [self removeRow:formRow];
}

-(Row *)rowAtIndex:(NSIndexPath *)indexPath
{
    if ((self.sections.count > indexPath.section) && [[self.sections objectAtIndex:indexPath.section] rows].count > indexPath.row){
        return [[[self.sections objectAtIndex:indexPath.section] rows] objectAtIndex:indexPath.row];
    }
    return nil;
}



-(NSIndexPath *)indexPathOfRow:(Row *)formRow
{
    Section * section = formRow.section;
    if (section){
        NSUInteger sectionIndex = [self.sections indexOfObject:section];
        if (sectionIndex != NSNotFound){
            NSUInteger rowIndex = [section.rows indexOfObject:formRow];
            if (rowIndex != NSNotFound){
                return [NSIndexPath indexPathForRow:rowIndex inSection:sectionIndex];
            }
        }
    }
    return nil;
}

#pragma mark - KVO

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (!self.delegate) return;
    if ([keyPath isEqualToString:@"sections"]){
        if ([[change objectForKey:NSKeyValueChangeKindKey] isEqualToNumber:@(NSKeyValueChangeInsertion)]){
            NSIndexSet * indexSet = [change objectForKey:NSKeyValueChangeIndexesKey];
            Section * section = [self.sections objectAtIndex:indexSet.firstIndex];
            [self.delegate sectionHasBeenAdded:section atIndex:indexSet.firstIndex];
        }
        else if ([[change objectForKey:NSKeyValueChangeKindKey] isEqualToNumber:@(NSKeyValueChangeRemoval)]){
            NSIndexSet * indexSet = [change objectForKey:NSKeyValueChangeIndexesKey];
            Section * removedSection = [[change objectForKey:NSKeyValueChangeOldKey] objectAtIndex:0];
            [self.delegate sectionHasBeenRemoved:removedSection atIndex:indexSet.firstIndex];
        }
    }
}

-(void)dealloc
{
    @try {
        [self removeObserver:self forKeyPath:@"sections"];
    }
    @catch (NSException * __unused exception) {}
}

#pragma mark - allSections KVO

//添加Section到allSections，并将section中的rows添加到allRowTag中
- (void)insertObject:(Section *)section inAllSectionsAtIndex:(NSUInteger)index {
    section.form = self;
    [self.sections insertObject:section atIndex:index];
    [section.rows enumerateObjectsUsingBlock:^(id obj, NSUInteger __unused idx, BOOL * __unused stop) {
        [self addRowToTagCollection:obj];
    }];
}

#pragma mark - private


-(NSMutableArray *)sections
{
    return _sections;
}

#pragma mark - Helpers

-(Row *)nextRowForRow:(Row *)row
{
    NSUInteger indexOfRow = [row.section.rows indexOfObject:row];
    if (indexOfRow != NSNotFound){
        if (indexOfRow + 1 < row.section.rows.count){
            return [row.section.rows objectAtIndex:++indexOfRow];
        }
        else{
            NSUInteger sectionIndex = [self.sections indexOfObject:row.section];
            NSUInteger numberOfSections = [self.sections count];
            if (sectionIndex != NSNotFound && sectionIndex < numberOfSections - 1){
                sectionIndex++;
                Section * sectionDescriptor;
                while ([[(sectionDescriptor = [row.section.form.sections objectAtIndex:sectionIndex]) rows] count] == 0 && sectionIndex < numberOfSections - 1){
                    sectionIndex++;
                }
                return [sectionDescriptor.rows firstObject];
            }
        }
    }
    return nil;
}


-(Row *)previousRowForRow:(Row *)row
{
    NSUInteger indexOfRow = [row.section.rows indexOfObject:row];
    if (indexOfRow != NSNotFound){
        if (indexOfRow > 0 ){
            return [row.section.rows objectAtIndex:--indexOfRow];
        }
        else{
            NSUInteger sectionIndex = [self.sections indexOfObject:row.section];
            if (sectionIndex != NSNotFound && sectionIndex > 0){
                sectionIndex--;
                Section * sectionDescriptor;
                while ([[(sectionDescriptor = [row.section.form.sections objectAtIndex:sectionIndex]) rows] count] == 0 && sectionIndex > 0 ){
                    sectionIndex--;
                }
                return [sectionDescriptor.rows lastObject];
            }
        }
    }
    return nil;
}

-(void)addRowToTagCollection:(Row*) rowDescriptor
{
    if (rowDescriptor.tag) {
        self.allRowsByTag[rowDescriptor.tag] = rowDescriptor;
    }
}

-(void)removeRowFromTagCollection:(Row *)rowDescriptor
{
    if (rowDescriptor.tag){
        [self.allRowsByTag removeObjectForKey:rowDescriptor.tag];
    }
}

@end
